﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AForge.Video.DirectShow;

using Graphene.Processing;
using Graphene.Storing;

namespace Graphene
{
    public delegate void SetByteImageInVideoPictureboxDelegate(byte[] byteImage);
    public delegate void SetBitmapInVideoPictureboxDelegate(System.Drawing.Bitmap bitmap);            

    class MarkerCalibrateController
    {
        public MarkerCalibrateController(Model mo, MainForm vi)
        {
            this.model = mo;
            this.view = vi;

            this.camerasRunning = false;

            this.view.RefreshVideoListButtonForMarkerCalibrationButton_SetClickedHandler(this.RefreshVideoListsForMarkerCalibration);
            this.view.VideoListPrimaryComboboxForMarkerCalibration_SetNewSelectionHandler(VideoListPrimaryForMarkerCalibration_NewSelection);
            this.view.VideoListSecondaryComboboxForMarkerCalibration_SetNewSelectionHandler(VideoListSecondaryForMarkerCalibration_NewSelection);
            this.view.StartStopCheckboxForMarkerCalibration_SetCheckChangedHandler(this.StartStopCalibrationCheckbox_CheckChanged);

            this.view.VideoPictureBoxPrimaryForMarkerCalibration_SetClickedHandler(this.VideoPictureBoxPrimaryForMarkerCalibration_Clicked);
            this.view.VideoPictureBoxSecondaryForMarkerCalibration_SetClickedHandler(this.VideoPictureBoxSecondaryForMarkerCalibration_Clicked);                        
            this.view.TolerancePrimaryTrackbar_SetValueChangedHandler(this.TolerancePrimaryTrackbar_ValueChanged);
            this.view.ToleranceSecondaryTrackbar_SetValueChangedHandler(this.ToleranceSecondaryTrackbar_ValueChanged);
            this.view.TolerancePrimaryTrackbar_ClickReleasedHandler(this.TolerancePrimaryTrackbar_ClickReleased);
            this.view.ToleranceSecondaryTrackbar_ClickReleasedHandler(this.ToleranceSecondaryTrackbar_ClickReleased);
            this.view.AddSampleButtonForMarkerCalibration_SetClickHandler(AddSampleButtonForMarkerCalibration_Clicked);
            this.view.SampleListboxForMarkerCalibration_SetSelectedValueChangedHandler(SampleListboxForMarkerCalibration_SelectedValueChanged);
            this.view.AddNewMarkerForMarkerCalibration_SetClickedHandler(this.AddNewMarkerButtonForMarkerCalibration_Clicked);
            this.view.RemoveSampleButtonForMarkerCalibration_SetClickHandler(this.RemoveSampleButtonForMarkerCalibration_Clicked);
            this.view.ClearSamplesButtonForMarkerCalibration_SetClickHandler(this.ClearSamplesButtonForMarkerCalibration_Clicked);
                          
            this.RefreshVideoListsForMarkerCalibration(this, EventArgs.Empty);
        }

        private void RefreshVideoListsForMarkerCalibration(object sender, EventArgs args)
        {
            this.model.RefreshAvailableVideoDeviceList();
            this.view.UpdateVideoListsForMarkerCalibration();
        }

        private void VideoListGeneralForMarkerCalibration_NewSelection(
            ComboBox comboBox,
            SetVideoSourceSelectionDelegate setVideoSourceSelectionCall
            )
        {
            if (comboBox.SelectedItem != null
                && !comboBox.Equals(MainForm.SELECTION_NONE))
            {
                string name = (string)comboBox.SelectedItem;
                FilterInfo filterInfo = this.model.SearchVideoDeviceByName(name);
                setVideoSourceSelectionCall(filterInfo);
            }
            else
            {
                setVideoSourceSelectionCall(null);
            }
            this.view.UpdateVideoListsForMarkerCalibration();
        }

        private void VideoListPrimaryForMarkerCalibration_NewSelection(object sender, EventArgs args)
        {
            VideoListGeneralForMarkerCalibration_NewSelection(
                this.view.VideoListComboboxPrimaryForMarkerCalibration,
                this.model.SetVideoSourceSelectionPrimaryForMarkerCalibration
                );
        }

        private void VideoListSecondaryForMarkerCalibration_NewSelection(object sender, EventArgs args)
        {
            VideoListGeneralForMarkerCalibration_NewSelection(
                this.view.VideoListComboboxSecondaryForMarkerCalibration,
                this.model.SetVideoSourceSelectionSecondaryForMarkerCalibration
                );
        }       

        private void StartStopCalibrationCheckbox_CheckChanged(object sender, EventArgs args)
        {
            if (((CheckBox)sender).CheckState.Equals(CheckState.Checked))
            {
                this.view.VideoListComboboxPrimaryForMarkerCalibration.Enabled = false;
                this.view.VideoListComboboxSecondaryForMarkerCalibration.Enabled = false;
                this.view.RefreshVideoListButtonForMarkerCalibration.Enabled = false;
                FilterInfo select1 = this.model.GetVideoSourceSelectionPrimaryForMarkerCalibration();
                FilterInfo select2 = this.model.GetVideoSourceSelectionSecondaryForMarkerCalibration();
                if (select1 == null || select2 == null)
                {
                    return;
                }
                string idPrimaryVideoSource = this.model.InitVideoSource(
                    select1.MonikerString,
                    "VideoSource-" + Model.GenerateId(),
                    select1.Name
                    );
                string idSecondaryVideoSource = this.model.InitVideoSource(
                    select2.MonikerString,
                    "VideoSource-" + Model.GenerateId(),
                    select2.Name
                    );                
                model.AddResultChangedHandlerToVideoSource(idPrimaryVideoSource, this.VideoSourcePrimary_NewFrame);
                model.AddResultChangedHandlerToVideoSource(idSecondaryVideoSource, this.VideoSourceSecondary_NewFrame);                
                this.camerasRunning = true;
                this.model.CalibratingMarkerPrimarySelected = false;
                this.model.CalibratingMarkerSecondarySelected = false;
                this.model.StartVideoSource(idPrimaryVideoSource);
                this.model.StartVideoSource(idSecondaryVideoSource);                
                this.view.StartStopCheckboxForMarkerCalibration.Text = MainForm.RUNNING_TEXT;                
            }
            else if (((CheckBox)this.view.MouselookCheckbox).CheckState.Equals(CheckState.Unchecked))
            {
                AForge.Video.DirectShow.FilterInfo select1 = this.model.GetVideoSourceSelectionPrimaryForMarkerCalibration();
                AForge.Video.DirectShow.FilterInfo select2 = this.model.GetVideoSourceSelectionSecondaryForMarkerCalibration();
                string idPrimaryVideoSource = this.model.SearchVideoSourceIdByName(select1.Name);
                string idSecondaryVideoSource = this.model.SearchVideoSourceIdByName(select2.Name);

                if (idPrimaryVideoSource == null || idSecondaryVideoSource == null)
                {                    
                    return;
                }
                this.model.StopVideoSource(idPrimaryVideoSource);
                this.model.StopVideoSource(idSecondaryVideoSource);                
                this.model.RemoveResultChangedHandlerToVideoSource(idPrimaryVideoSource, this.VideoSourcePrimary_NewFrame);
                this.model.RemoveResultChangedHandlerToVideoSource(idSecondaryVideoSource, this.VideoSourceSecondary_NewFrame);                
                this.model.CloseVideoSource(idPrimaryVideoSource);
                this.model.CloseVideoSource(idSecondaryVideoSource);               

                this.camerasRunning = false;
                this.model.StopVideoSource(idPrimaryVideoSource);
                this.model.StopVideoSource(idSecondaryVideoSource);
                this.view.StartStopCheckboxForMarkerCalibration.Text = MainForm.STOPPED_TEXT;
                this.view.VideoListComboboxPrimaryForMarkerCalibration.Enabled = true;
                this.view.VideoListComboboxSecondaryForMarkerCalibration.Enabled = true;
                this.view.RefreshVideoListButtonForMarkerCalibration.Enabled = true;
            }
        }

        private void VideoSourceGeneral_NewFrame(
            object sender,
            PictureBox pictureBox,
            SetImageInPictureboxDelegate setImageInVideoPictureboxCall,
            SetByteImageInVideoPictureboxDelegate setByteImageInVideoPictureboxCall,
            SetBitmapInVideoPictureboxDelegate setBitmapInVideoPictureboxCall
            )
        {
            VideoSource senderVideoSource = (VideoSource)sender;
            if (!this.camerasRunning || (object)senderVideoSource == null)
            {
                return;
            }

            string deviceId = senderVideoSource.MyId;
            byte[] byteImage = (byte[])senderVideoSource.ResultData;
            System.Drawing.Bitmap bitmap = senderVideoSource.Bitmap;

            if (bitmap != null && byteImage != null)
            {
                byte[] resizedByteImage = AbstractProcessor.Resize(
                    byteImage,
                    bitmap.Width,
                    bitmap.Height,
                    pictureBox.Size.Width,
                    pictureBox.Size.Height
                    );
                System.Drawing.Bitmap resizedBitmap = AbstractProcessor.ByteImageToBitmap_Unsafe(
                    resizedByteImage,
                    pictureBox.Size.Width,
                    pictureBox.Size.Height
                    );
                setImageInVideoPictureboxCall(resizedBitmap);
                setByteImageInVideoPictureboxCall(byteImage);
                setBitmapInVideoPictureboxCall(bitmap);
            }
            else
            {
                setImageInVideoPictureboxCall(global::Graphene.Properties.Resources.o_small_02);                
                setByteImageInVideoPictureboxCall(null);
                setBitmapInVideoPictureboxCall(null);
            }
        }
        
        private void VideoSourcePrimary_NewFrame(object sender, object whatChanged)
        {
            VideoSourceGeneral_NewFrame(
                sender,
                this.view.VideoPrimaryPictureboxForMarkerCalibration,
                this.view.SetImageInPrimaryVideoPictureBoxForMarkerCalibration,
                this.model.SetByteImageInPrimaryVideoPictureboxForMarkerCalibration,
                this.model.SetBitmapInPrimaryVideoPictureboxForMarkerCalibration
            );
        }

        private void VideoSourceSecondary_NewFrame(object sender, object whatChanged)
        {
            VideoSourceGeneral_NewFrame(
                sender,
                this.view.VideoSecondaryPictureboxForMarkerCalibration,
                this.view.SetImageInSecondaryVideoPictureBoxForMarkerCalibration,
                this.model.SetByteImageInSecondaryVideoPictureboxForMarkerCalibration,
                this.model.SetBitmapInSecondaryVideoPictureboxForMarkerCalibration
            );
        }
        
        private void VideoPictureBoxPrimaryForMarkerCalibration_Clicked(object sender, EventArgs args)
        {                        
            if (this.model.GetBitmapInPrimaryVideoPictureboxForMarkerCalibration() == null
                || this.model.GetByteImageInPrimaryVideoPictureboxForMarkerCalibration() == null
                || this.camerasRunning                
                )
            {
                return;
            }

            this.DrawXPrimary();
            this.FilterSamplePrimary();
        }
                    
        private void DrawXPrimary()
        {
            /* Recording mouse position. */
            System.Drawing.Point relativeMousePosition = this.view.PrimaryVideoPictureBoxForMarkerCalibrationPointToClient(Control.MousePosition);

            /* Getting the captured images. */
            System.Drawing.Bitmap bitmap = this.model.GetBitmapInPrimaryVideoPictureboxForMarkerCalibration();
            byte[] byteImage = this.model.GetByteImageInPrimaryVideoPictureboxForMarkerCalibration();

            int markedX = bitmap.Width * relativeMousePosition.X / view.VideoPrimaryPictureboxForMarkerCalibration.Size.Width;
            int markedY = bitmap.Height * relativeMousePosition.Y / view.VideoPrimaryPictureboxForMarkerCalibration.Size.Height;

            /* Getting the color. */
            int address = 3 * (bitmap.Width * markedY + markedX);
            System.Drawing.Color markedColor = System.Drawing.Color.FromArgb(byteImage[address + 2], byteImage[address + 1], byteImage[address]);
            this.model.CalibratingMarkerPrimaryPosition = new PointInt2D(markedX, markedY);
            this.model.CalibratingMarkerPrimaryColor = markedColor;
            this.model.CalibratingMarkerPrimarySelected = true;

            /* Processing images. */
            byte[] markedByteImage = new byte[bitmap.Width * bitmap.Height * 3];
            byteImage.CopyTo(markedByteImage, 0);
            markedByteImage = AbstractProcessor.ResizeAndFadeToColor(
                markedByteImage,
                bitmap.Width,
                bitmap.Height,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y,
                System.Drawing.Color.FromArgb(0, 0, 0),
                1.0
            );
            markedByteImage = AbstractProcessor.DrawX(
                markedByteImage,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y,
                new Graphene.Storing.PointInt2D(relativeMousePosition.X, relativeMousePosition.Y),
                System.Drawing.Color.White
            );
            System.Drawing.Bitmap markedBitmap = AbstractProcessor.ByteImageToBitmap_Unsafe(
                markedByteImage,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y
            );

            /* Setting the image. */
            this.view.SetImageInPrimaryVideoPictureBoxForMarkerCalibration(markedBitmap);
        }
        
        
        private void VideoPictureBoxSecondaryForMarkerCalibration_Clicked(object sender, EventArgs args)
        {
            if (this.model.GetBitmapInSecondaryVideoPictureboxForMarkerCalibration() == null
                || this.model.GetByteImageInSecondaryVideoPictureboxForMarkerCalibration() == null
                || this.camerasRunning                        
                )
            {
                return;
            }

            this.DrawXSecondary();
            this.FilterSampleSecondary();
        }        

        private void DrawXSecondary()
        {
            /* Recording mouse position. */
            System.Drawing.Point relativeMousePosition = this.view.SecondaryVideoPictureBoxForMarkerCalibrationPointToClient(Control.MousePosition);
        
            /* Getting the captured images. */
            System.Drawing.Bitmap bitmap = this.model.GetBitmapInSecondaryVideoPictureboxForMarkerCalibration();
            byte[] byteImage = this.model.GetByteImageInSecondaryVideoPictureboxForMarkerCalibration();

            int markedX = bitmap.Width * relativeMousePosition.X / MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X;
            int markedY = bitmap.Height * relativeMousePosition.Y / MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y;

            /* Getting the color. */
            int address = 3 * (bitmap.Width * markedY + markedX);
            System.Drawing.Color markedColor = System.Drawing.Color.FromArgb(byteImage[address + 2], byteImage[address + 1], byteImage[address]);
            this.model.CalibratingMarkerSecondaryColor = markedColor;
            this.model.CalibratingMarkerSecondaryPosition = new PointInt2D(markedX, markedY);
            this.model.CalibratingMarkerSecondarySelected = true;

            /* Processing images. */
            byte[] markedByteImage = new byte[bitmap.Width * bitmap.Height * 3];
            byteImage.CopyTo(markedByteImage, 0);
            markedByteImage = AbstractProcessor.ResizeAndFadeToColor(
                markedByteImage,
                bitmap.Width,
                bitmap.Height,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y,
                System.Drawing.Color.FromArgb(0, 0, 0),
                1.0
            );
            markedByteImage = AbstractProcessor.DrawX(
                markedByteImage,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y,
                new Graphene.Storing.PointInt2D(relativeMousePosition.X, relativeMousePosition.Y),
                System.Drawing.Color.White
            );
            System.Drawing.Bitmap markedBitmap = AbstractProcessor.ByteImageToBitmap_Unsafe(
                markedByteImage,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y
            );

            /* Setting the image. */
            this.view.SetImageInSecondaryVideoPictureBoxForMarkerCalibration(markedBitmap);
        }
    
        private void FilterSamplePrimary()
        {
            if (!this.model.CalibratingMarkerPrimarySelected
                || this.model.GetBitmapInPrimaryVideoPictureboxForMarkerCalibration() == null
                || this.model.GetByteImageInPrimaryVideoPictureboxForMarkerCalibration() == null
                || this.camerasRunning                
                )
            {
                return;
            }

            /* Getting the captured images. */
            System.Drawing.Bitmap bitmap = this.model.GetBitmapInPrimaryVideoPictureboxForMarkerCalibration();
            byte[] byteImage = this.model.GetByteImageInPrimaryVideoPictureboxForMarkerCalibration();

            /* Processing the image. */        
            byte[] filteredByteImage = new byte[bitmap.Width * bitmap.Height * 3];
            this.model.SampleBadnessPrimary = AbstractProcessor.HighlightMarkerFromBackground(
                byteImage,
                filteredByteImage,
                new PointInt2D(bitmap.Width, bitmap.Height),
                model.CalibratingMarkerPrimaryPosition,
                model.CalibratingMarkerPrimaryColor,
                System.Drawing.Color.YellowGreen,
                System.Drawing.Color.HotPink,
                System.Drawing.Color.DarkSlateGray,
                this.model.TolerancePrimaryForMarkerCalibration,
                (byte)(this.model.TolerancePrimaryForMarkerCalibration * 1.3f)
            );
            byte[] resizedFilteredByteImage = new byte[MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X * MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y * 3];
            resizedFilteredByteImage = AbstractProcessor.ResizeAndFadeToColor(
                filteredByteImage,
                bitmap.Width,
                bitmap.Height,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y,
                System.Drawing.Color.FromArgb(0, 0, 0),
                1.0
            );
            System.Drawing.Bitmap resizedFilteredBitmap = AbstractProcessor.ByteImageToBitmap_Unsafe(
                resizedFilteredByteImage,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y
            );

            /* Showing the image. */
            this.view.SetImageInPrimaryFilteredPictureBoxForMarkerCalibration(resizedFilteredBitmap);

            /* Comparing with other markers. */
            bool similarExists = false;
            foreach (MarkerInImage otherMarker in this.model.MarkersFor3D.Keys)
            {
                if (AbstractProcessor.CompareColor(otherMarker.Color, model.CalibratingMarkerPrimaryColor, this.model.TolerancePrimaryForMarkerCalibration))
                {
                    similarExists = true;
                }
            }
            if (model.SampleBadnessPrimary > 0.0002f || similarExists)
            {
                view.AcceptablePrimaryLabel.Text = MainForm.NOT_ACCEPTABLE_TEXT;
                view.AcceptablePrimaryLabel.ForeColor = System.Drawing.Color.Maroon;
                view.AddSampleButtonForMarkerCalibration.Enabled = false;
            }
            else
            {
                view.AcceptablePrimaryLabel.Text = MainForm.ACCEPTABLE_TEXT;
                view.AcceptablePrimaryLabel.ForeColor = System.Drawing.Color.Green;
                if (this.model.SampleBadnessSecondary <= 0.0002f)
                {
                    view.AddSampleButtonForMarkerCalibration.Enabled = true;
                }
            }
        }

        private void FilterSampleSecondary()
        {
            if (!this.model.CalibratingMarkerSecondarySelected
                || this.model.GetBitmapInSecondaryVideoPictureboxForMarkerCalibration() == null
                || this.model.GetByteImageInSecondaryVideoPictureboxForMarkerCalibration() == null
                || this.camerasRunning
                )
            {
                return;
            }

            /* Getting the captured images. */
            System.Drawing.Bitmap bitmap = this.model.GetBitmapInSecondaryVideoPictureboxForMarkerCalibration();
            byte[] byteImage = this.model.GetByteImageInSecondaryVideoPictureboxForMarkerCalibration();

            /* Processing the image. */
            byte[] filteredByteImage = new byte[bitmap.Width * bitmap.Height * 3];            
            this.model.SampleBadnessSecondary = AbstractProcessor.HighlightMarkerFromBackground(
                byteImage,
                filteredByteImage,
                new PointInt2D(bitmap.Width, bitmap.Height),
                model.CalibratingMarkerSecondaryPosition,
                model.CalibratingMarkerSecondaryColor,
                System.Drawing.Color.YellowGreen,
                System.Drawing.Color.HotPink,
                System.Drawing.Color.DarkSlateGray,
                this.model.ToleranceSecondaryForMarkerCalibration,
                (byte)(this.model.ToleranceSecondaryForMarkerCalibration * 1.3f)
            );
            byte[] resizedFilteredByteImage = new byte[MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X * MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y * 3];
            resizedFilteredByteImage = AbstractProcessor.ResizeAndFadeToColor(
                filteredByteImage,
                bitmap.Width,
                bitmap.Height,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y,
                System.Drawing.Color.FromArgb(0, 0, 0),
                1.0
            );
            System.Drawing.Bitmap resizedFilteredBitmap = AbstractProcessor.ByteImageToBitmap_Unsafe(
                resizedFilteredByteImage,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.X,
                MainForm.VIEWFINDER_SIZE_FOR_MARKER_CALIBRATION.Y
            );

            /* Showing the image. */
            this.view.SetImageInSecondaryFilteredPictureBoxForMarkerCalibration(resizedFilteredBitmap);

            /* Comparing with other markers. */
            bool similarExists = false;
            foreach (MarkerInImage otherMarker in this.model.MarkersFor3D.Values)
            {
                if (AbstractProcessor.CompareColor(otherMarker.Color, model.CalibratingMarkerSecondaryColor, this.model.ToleranceSecondaryForMarkerCalibration))
                {
                    similarExists = true;
                }
            }

            if (this.model.SampleBadnessSecondary > 0.0002f || similarExists)
            {
                view.AcceptableSecondaryLabel.Text = MainForm.NOT_ACCEPTABLE_TEXT;
                view.AcceptableSecondaryLabel.ForeColor = System.Drawing.Color.Maroon;
                view.AddSampleButtonForMarkerCalibration.Enabled = false;
            }
            else
            {                
                view.AcceptableSecondaryLabel.Text = MainForm.ACCEPTABLE_TEXT;
                view.AcceptableSecondaryLabel.ForeColor = System.Drawing.Color.Green;
                if (this.model.SampleBadnessPrimary <= 0.0002f)
                {
                    view.AddSampleButtonForMarkerCalibration.Enabled = true;
                }
            }
        }

        private void TolerancePrimaryTrackbar_ValueChanged(object sender, EventArgs args)
        {
            this.model.TolerancePrimaryForMarkerCalibration = (byte)this.view.TolerancePrimaryTrackbar.Value;
            this.view.TolerancePrimaryLabel.Text = this.model.TolerancePrimaryForMarkerCalibration.ToString();            
        }
        private void ToleranceSecondaryTrackbar_ValueChanged(object sender, EventArgs args)
        {
            this.model.ToleranceSecondaryForMarkerCalibration = (byte)this.view.ToleranceSecondaryTrackbar.Value;
            this.view.ToleranceSecondaryLabel.Text = this.model.ToleranceSecondaryForMarkerCalibration.ToString();
        }

        private void TolerancePrimaryTrackbar_ClickReleased(object sender, EventArgs args)
        {
            FilterSamplePrimary();
        }
        public void ToleranceSecondaryTrackbar_ClickReleased(object sender, EventArgs args)
        {
            FilterSampleSecondary();
        }

        private void AddSampleButtonForMarkerCalibration_Clicked(object sender, EventArgs args)
        {
            if (!this.model.CalibratingMarkerPrimarySelected
                || !this.model.CalibratingMarkerSecondarySelected)
            {
                return;
            }

            string primaryId = Model.GenerateId();
            MarkerInImage markerPrimary = new MarkerInImage(
                "MarkerInImage-" + primaryId,
                "MarkerInImage-" + primaryId,
                this.model.CalibratingMarkerPrimaryColor,
                this.model.TolerancePrimaryForMarkerCalibration,
                0,
                this.model.CalibratingMarkerPrimaryColor
            );
            string secondaryId = Model.GenerateId();
            MarkerInImage markerSecondary = new MarkerInImage(
                "MarkerInImage-" + secondaryId,
                "MarkerInImage-" + secondaryId,
                this.model.CalibratingMarkerSecondaryColor,
                this.model.ToleranceSecondaryForMarkerCalibration,
                0,
                this.model.CalibratingMarkerSecondaryColor
            );
            this.model.AddSampleToListForMarkerCalibration(markerPrimary, markerSecondary);
            string newItem = markerPrimary.ToString() + " and " + markerSecondary.ToString();
            this.view.SampleListboxForMarkerCalibration.Items.Add(newItem);             
            int i = this.view.SampleListboxForMarkerCalibration.Items.IndexOf(newItem);
            this.view.SampleListboxForMarkerCalibration.SetSelected(i, true);
        }                            

        private void SampleListboxForMarkerCalibration_SelectedValueChanged(object sender, EventArgs args)
        {            
            if (this.view.SampleListboxForMarkerCalibration.SelectedIndex < 0)
            {
                this.view.ColorSamplePictureboxPrimaryForMarkerCalibration.BackColor = System.Drawing.Color.White;
                this.view.ColorSamplePictureboxSecondaryForMarkerCalibration.BackColor = System.Drawing.Color.White;
                return;
            }
            KeyValuePair<MarkerInImage, MarkerInImage> selected = this.model.ElementAtSampleListForMarkerCalibration(this.view.SampleListboxForMarkerCalibration.SelectedIndex);            
            MarkerInImage markerPrimary = selected.Key;
            MarkerInImage markerSecondary = selected.Value;
            this.view.ColorSamplePictureboxPrimaryForMarkerCalibration.BackColor = markerPrimary.Color;
            this.view.ColorSamplePictureboxSecondaryForMarkerCalibration.BackColor = markerSecondary.Color;
        }

        private void AddNewMarkerButtonForMarkerCalibration_Clicked(object sender, EventArgs args)
        {
            if (this.model.CountOfListOfMarkerSamplesFor3DMarkerCalibration() <= 0)
            {
                return;
            }

            KeyValuePair<MarkerInImage, MarkerInImage> markerPair = this.model.GetAverageFromListFor3DMarkerCalibration();
            this.model.AddMarkerToMarkers3D(markerPair);            
        }

        private void RemoveSampleButtonForMarkerCalibration_Clicked(object sender, EventArgs args)
        {
            if (this.view.SampleListboxForMarkerCalibration.SelectedItem == null)
            {
                return;
            }

            string combinedIds = (string)this.view.SampleListboxForMarkerCalibration.SelectedItem;
            int i = combinedIds.IndexOf(" and ");
            string primaryId = combinedIds.Substring(0, i);
            string secondaryId = combinedIds.Substring(i + 5, combinedIds.Length - i - 5);
            this.model.RemoveSampleFromListForMarkerCalibration(primaryId, secondaryId);
            this.view.SampleListboxForMarkerCalibration.Items.Remove(combinedIds);
        }

        private void ClearSamplesButtonForMarkerCalibration_Clicked(object sender, EventArgs args)
        {
            this.model.ClearSamplesForMarkerCalibration();
            //should be after model
            this.view.SampleListboxForMarkerCalibration.Items.Clear();
        }         

        private Model model;
        private MainForm view;

        private bool camerasRunning;
    }
}
